package cn.tedu.charging.order.quartz;

import cn.tedu.charging.order.dao.mapper.OrderSuccessMapper;
import cn.tedu.charging.order.dao.repository.OrderRepository;
import cn.tedu.charging.order.pojo.po.ChargingOrderFailPO;
import cn.tedu.charging.order.pojo.po.ChargingOrderSuccessPO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.UUID;

@Slf4j
public class DeviceCheckJob implements Job {

    /**
     * 必须有一个无参数的构造器
     *  如果没有， 在初始化 new DeviceCheckJob 调用 Class newInstance 实例化，通过无参的构造器实例化对象
     *  getConstructor0() 获取无参构造器
     *  public DeviceCheckJob(String orderNo, Integer gunId) 覆盖 默认的无参构造器
     *  找不到方法 抛异常 NoSuchMethodException  找不到构造器，创建不了 DeviceCheckJob对象
     */
    public DeviceCheckJob() {
    }


    public DeviceCheckJob(String orderNo, Integer gunId) throws SchedulerException {
        log.debug("添加设备自检定时任务,订单号:{},枪id:{}",orderNo,gunId);

        //创建调度器工厂
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        //获取调度器
        Scheduler scheduler = schedulerFactory.getScheduler();

        //任务详情
        JobDetail jobDetail = JobBuilder.newJob(DeviceCheckJob.class)
                //定义定时任务的名称 和 组 分类
                .withIdentity("device-check-job" + UUID.randomUUID(),
                        "device-check-job-group")
                //传入订单号，任务执行的时候使用 execute方法被调用
                .usingJobData("orderNo",orderNo)
                //传入枪id，任务执行的时候使用 execute方法被调用
                .usingJobData("gunId",gunId)
                .build();
        //获取当前时间
        long now = System.currentTimeMillis();
        //任务的执行时间为 当前时间的一分钟以后
        long deviceCheckTime = now + 60 * 1000;
        //把时间戳 转换成 java.util.Date对象
        Date triggerTime = new Date(deviceCheckTime);

        //定义触发器 1分钟以后触发
        Trigger trigger = TriggerBuilder.newTrigger()
                .startAt(triggerTime)
                .build();

        //调度器 把任务和触发器进行绑定
        //调度器 scheduler,让任务 JobDetail 和 按照 触发器的 时间 来触发
        scheduler.scheduleJob(jobDetail,trigger);
        //启动调度器
        scheduler.start();

    }

    /**
     * Quartz 调度器调用这个方法
     * 来执行具体的业务
     *
     * 7. 判断是否有订单记录
     * 8. 有成功订单记录 订单状态是 充电中 说明设备 有响应，设备收到了指令后，正常的返回开始充电成功的响应，保存成功订单记录  无需处理
     * 9. 没有成功订单记录  ，要判断是否有失败订单记录
     * 10. 有失败订单记录  失败原因 有响应-无法充电  无需处理
     * 11. 没有成功订单记录 也 没有失败订单记录
     * 12. 插入失败订单记录 失败原因 设备无响应 通知用户和维修人员
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.debug("设备自检任务开始执行");
        //jobExecutionContext 获取任务详情中的数据对象 jobDataMap
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        //获取订单号
        String orderNo = jobDataMap.getString("orderNo");
        //获取枪id
        Integer gunId = jobDataMap.getInt("gunId");
        log.debug("设备自检任务-获取订单号:{},枪id:{}",orderNo,gunId);
        //不在容器中的DeviceCheckJob 想要使用容器中的mapper 来处理数据
        //可以参考 mqtt和mqttConsumer 通过构造器或者通过setter方法注入
        //OrderSuccessMapper orderSuccessMapper = SpringContextUtils.getBean(OrderSuccessMapper.class);
        //OrderFailMapper orderFailMapper = SpringContextUtils.getBean(OrderFailMapper.class);
        OrderRepository orderRepository = SpringContextUtils.getBean(OrderRepository.class);

        log.debug("查询成功订单记录:订单号{}",orderNo);
        ChargingOrderSuccessPO chargingOrderSuccessPO = orderRepository.getSuccessOrder(orderNo);
        log.debug("查询成功订单记录:订单号{},结果{}",orderNo,chargingOrderSuccessPO);
        //判断是否有成功订单记录
        if(chargingOrderSuccessPO != null){
            //没有成功订单记录
            log.debug("没有成功订单记录，查询是否有失败订单记录");
            log.debug("查询失败订单记录:订单号{}",orderNo);
            ChargingOrderFailPO chargingOrderFailPO = orderRepository.getFailOrder(orderNo);
            log.debug("查询失败订单记录:订单号{},结果:{}",orderNo,chargingOrderFailPO);
            //判断是否有失败订单记录
            if (chargingOrderFailPO == null) {
                //没有失败订单记录，也没有成功订单记录，插入失败订单记录 同时记录失败原因
                ChargingOrderFailPO failPO = new ChargingOrderFailPO();
                failPO.setBillId(orderNo);
                failPO.setFailDesc("设备自检失败-设备无响应");
                log.debug("插入失败订单记录:{}",failPO);
                Integer row = orderRepository.saveFailOrder(failPO);
                log.debug("插入失败订单记录:{},影响行数:{}",failPO,row);
                log.debug("设备自检失败-设备无响应，通知用户和维修人员");
                log.debug("给用户发送优惠券 表示歉意 给用户心灵上的安慰");
            }else {
                log.debug("有失败订单记录，失败原因:{}",chargingOrderFailPO.getFailDesc());
                log.debug("无需处理");
            }
        }else {
            log.debug("有成功订单记录，订单状态是 充电中");
            log.debug("无需处理");
        }
    }
}
